<?php
/**
 * Created by PhpStorm.
 * UsersF: Mloong
 * Date: 2019/2/21
 * Time: 9:50
 */

namespace app\api\service;


use app\api\controller\v1\Lqb;
use app\api\model\Account;
use app\api\model\Popularize;
use app\api\model\Registered;
use app\api\model\UserTrue;
use app\common\controller\Info;
use app\common\controller\UserPhone;
use app\common\model\Error;
use app\common\service\getPhoneInfoService;
use app\lib\exception\MysqlErrorException;
use app\lib\exception\ParameterException;
use app\lib\exception\ServerException;
use app\login\service\ShowService;
use Driver\Cache\Redis;
use think\Db;
use think\Exception;
use think\facade\Request;

class popularizeService
{
    private $user_id;

    # 从redis写入到mysql(流量)
    public function listPopularizeToMysql($list_arr)
    {
        $arr = [];
        foreach ($list_arr as $json){
            $post_data = json_decode($json, true);
            $result = $this->recordPopularize($post_data['from'], $post_data['sign'], $post_data['ip'], $post_data['record_id'], $post_data['type']);
            array_push($arr, $result);
        }

        return $arr;
    }

    # 从redis写入到mysql(注册)
    public function listRegisteredToMysql($list_arr)
    {
        $arr = [];
        foreach ($list_arr as $json){
            $post_data = json_decode($json, true);
            $result = $this->writeRegistered($post_data['record_id'], $post_data['phone'], $post_data['ip'], $post_data['type']);
            array_push($arr, $result);
        }

        return $arr;
    }

    # 暂时先用实时更新
    public function _writeRegistered($data)
    {
        $result = $this->writeRegistered($data['record_id'], $data['phone'], $data['ip'], $data['type']);
        return $result;
    }

    /**
     * 记录推广来源 , 向mysql插入一条数据
     * @param $from 推广来源账号
     * @param $sign 标识
     */
    private function recordPopularize($from, $sign, $ip, $record_id, $type)
    {
        $redis_key = config('redis.all_sign').$from;
        if(Redis::sismember($redis_key, $sign) == false){
            return '标识已被禁用';
        }
        $redis_set_key = config('ips').$from;
        if(Redis::sismember($redis_set_key, $ip)){
            return 'ip has';
        }
        if($this->checkFrom($from) == false){
            return 'from不存在';
        }
        $bool = $this->_checkRedisSignAndIp($from, $sign, $ip);
        if($bool !== 'success'){
            return $bool;
        }
        # 把每一个$record_id 写入到redis_set中 为了提高注册吃准确率
        # Redis::sAdd(config('redis.record_id'), $record_id);
        # 推广记录写入数据库
        $this->findTodayIP($from, $sign, $ip, $record_id, $type);
        return true;
    }

    /**
     * 注册成功的主要逻辑(允许平台出现重复的手机号码)
     * @param $record_id from_sign_time组成的字段
     * @param $phone 手机号码
     * @param $ip 进来的ip
     * @param $type 贷款类型
     * @param $Repeat 是否允许重复
     * @throws MysqlErrorException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private function writeRegistered($record_id, $phone, $ip, $type)
    {
        # 先对 record_id 参数进行校验
        $arr_record_id = $this->with_record_id($record_id);

//        $bool = $this->check_record_id($arr_record_id);
//        if($bool !== 'success'){
//            return $bool;
//        }

        $from_url = "未知";
        $header = Request::header();
        if(array_key_exists('referer', $header) == true){
            $from_url = $header['referer'];
        }
        $arr = $this->getRepeat($record_id);
        $repeat = $arr['repeat'];
        $logo = $arr['logo'];
        if($repeat == -1){
            return false;
        }
        $model = new Registered();
        $data = [
            'from' => $arr_record_id['name'] == false ? null : $arr_record_id['name'],
            'sign' => $arr_record_id['sign'] == false ? null : $arr_record_id['sign'],
            'registered_time' => $arr_record_id['timestamp'] == false ? now_time() : date("Y-m-d H:i:s",$arr_record_id['timestamp']),
            'record_id' => $record_id,
            'add_time' => now_time(),
            'phone' => $phone,
            'ip' =>$ip,
            'url' => $from_url,
            'type' => $type,
            'address' => getAddress($ip),
            'logo' => $logo,
            'user_id' => $this->user_id
        ];
//        $has_phone = $this->findPhone($model, $phone, $arr_record_id['name'], $type);
        $has_phone = $this->checkHasPhone($phone, $type, $logo, $arr_record_id['timestamp']);
        # 添加手机号码到ture数据库
        $this->addPhoneToTrue($phone, $logo);
        if($repeat == '1' || $repeat == 1){
            # 标识允许在整个平台中出现重复的手机号码
            $result = $this->phoneAllowRepeat($model, $has_phone, $data);
        }
        if($repeat == '0' || $repeat == 0){
            # 标识不允许在整个平台中出现重复的手机号码
            $result = $this->phoneNoRepeat($model, $has_phone, $data);
        }
        return $result;
    }

    /**
     * 允许平台中出现重复的手机号码
     * @param $model 注册记录表对应模型
     * @param $has_phone 是否查询到手机号码
     * @param $data 插入的数据
     * @return bool
     * @throws MysqlErrorException
     */
    private function phoneAllowRepeat($model, $has_phone, $data)
    {
        Db::startTrans();
        try{
            Db::commit();
            if($has_phone){
                # 如果注册记录表查询到手机号码， 则添加一条数据， 添加字段first为 2
                $data['first'] = 2;
                $model->create($data);
            }else{
                # 如果注册记录表没有查询到手机号码， 则添加一条数据， 添加字段first为 1
                $data['first'] = 1;
                $model->create($data);
            }
        }catch (Exception $e){
            Db::rollback();
            $data = [
                'error_data' => '添加（允许）注册记录失败',
            ];
            Error::addErrorLog($data);
            return false;
        }
        return 'Repeat success';
    }
    /**
     * 不允许平台中出现重复的手机号码
     * @param $model 注册记录表对应模型
     * @param $has_phone 是否查询到手机号码
     * @param $data 插入的数据
     * @return bool
     * @throws MysqlErrorException
     */
    private function phoneNoRepeat($model, $has_phone, $data)
    {
        Db::startTrans();
        try{
            Db::commit();
            if($has_phone){
                # 如果注册记录表查询到手机号码， 则添加一条数据， 添加字段first为 2
                $data['first'] = -1;
            }else{
                # 如果注册记录表没有查询到手机号码， 则添加一条数据， 添加字段first为 1
                $data['first'] = 1;
            }
            $model->create($data);
        }catch (Exception $e){
            Db::rollback();
            # 写入list错误的列表
            Redis::lpush(config('redis.reg_error'), $data);
            $data = [
                'error_data' => '添加（不允许重复）注册记录失败',
            ];
            Error::addErrorLog($data);
            return false;
        }
        Redis::rpop(config('redis.reg'));
        return 'No Repeat success';
    }

    # 查询某个ip当天是否在某个账户下的某个渠道出现过
    private function findTodayIP($from, $sign, $ip, $record_id, $type)
    {
        $model = new Popularize();
        $find_one =  $model->where('from','=',$from)
            ->where('sign', '=', $sign)
            ->whereTime('add_time','today')
            ->where('type', '=', $type)
            ->where('ip', '=', $ip)
            ->find();
        $data = [
            'user_id' => $this->user_id,
            'from' =>$from,
            'sign' => $sign,
            'ip' => $ip,
            'record_id' => $record_id,
            'address' => getAddress($ip),
            'add_time' => now_time(),
            'type' => $type
        ];
        try{
            Db::startTrans();
            if(!$find_one){
                $result = $model->create($data);
            }else{
                $find_one->ip_count = Db::raw('ip_count+1');
                $find_one->update_time = now_time();
                $find_one->save();
                $result = true;
            }
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            $data = [
                'error_data' => 'List向Mysql插入失败（进来的链接）',
            ];
            # 记录没有添加到MySQL的数据
            Redis::lpush(config('redis.pop_error'), json_encode($data));
            Error::addErrorLog($data);

        }
        Redis::rpop(config('redis.pop'));
        return $result;
    }

    # 对$record_id 这个参数进行处理
    private function with_record_id($record_id)
    {
        if($record_id == null || $record_id == 'null'){
            return false;
        }
        $arr = explode('_', $record_id);
        if(count($arr) !== 3){
            return false;
        }
        $arr = [
            'name' => $arr[0],
            'sign' => $arr[1],
            'timestamp' => $arr[2],
            'id' => $record_id
        ];
        $redis_key = config('redis.all_sign').$arr['name'];
        if(Redis::sismember($redis_key, $arr['sign']) == false){
            throw new ParameterException([
                'msg'=> '标识被禁用'
            ]);
        }
        return $arr;
    }

    /**
     * 检查from是否存在 首先在redis查找 如果查找不到则在mysql查找
     * @param $from 推广来源账号
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private function checkFrom($from)
    {
        $redis_popularize_key = config('redis.popularize_key');
        $redis_from = Redis::sismember($redis_popularize_key,$from);

        if($redis_from == false){
            $model = new Account();
            $result =  $model->where('name', '=', $from)
                ->where('status','=', 1)
                ->find();
            if($result){
                Redis::sAdd($redis_popularize_key, $from);
               return true;
            }else{
                return false;
            }
        }else{
            return true;
        }
    }

    /**
     * 废弃
     * 先在redis查找hash中域的内容 如果找不到值 则插mysql然后再同步写入redis
     * @param $from 推广方
     * @param $sign 限制标识码
     * @param $ip ip黑名单
     */
    private function checkRedisSignAndIp($from, $sign, $ip)
    {
        $hash_key = config('redis.sign');
        $hash_field_sign = $from.'_sign'; # redis-hash里面的域（field）
        $hash_value_ip = $from.'_ip';   # redis-hash里面的域（field）
        # 如果redis-hash里面域不存在，则先查找mysql并同步写入redis
        if(Redis::hExists($hash_key, $hash_field_sign) == false || Redis::hExists($hash_key,$hash_value_ip) == false){
            $model = new Account();
            $result = $model->where('name','=',$from)
                ->find();

            $bool = $this->handleArr($result['sign'], $sign, $result['ip'], $ip);
            $arr = [
                $hash_field_sign => $result['sign'],
                $hash_value_ip => $result['ip']
            ];
            Redis::hMset($hash_key, $arr);
            if($bool == true){
                return true;
            }
            return $bool;
        }else{
            $sign_str = Redis::hget($hash_key,$hash_field_sign);
            $sign_ip = Redis::hget($hash_key,$hash_value_ip);
            $bool = $this->handleArr($sign_str, $sign, $sign_ip, $ip);
            if($bool == 'success'){
                return true;
            }
            return $bool;
        }
    }

    /**
     * 检查sign和ip是否是合法的
     * @param $from 推广方
     * @param $sign 标识码
     * @param $ip 进来的ip
     * @return bool
     * @throws MysqlErrorException
     */
    private function _checkRedisSignAndIp($from, $sign, $ip)
    {
        # 先从redis查找出对应账号的属性
        $redis_hash_key = config('redis.account').$from;
        $arr_info = Redis::hget($redis_hash_key);
        # 如果redis没有中对应的账号信息存在sign和ip，则从mysql读取并同步写入到redis
        if($arr_info && array_key_exists('sign', $arr_info) && array_key_exists('ip', $arr_info)){
            $sign_str = $arr_info['sign'];
            $sign_ip = $arr_info['ip'];
            $this->user_id = $arr_info['id'];
            $bool = $this->handleArr($sign_str, $sign, $sign_ip, $ip);
        }else{
            # 从mysql读取并写入到redis
            $model = new Account();
            try{
                $result = $model->where('name','=',$from)
                    ->find()
                    ->toArray();
            }catch (Exception $e){
                $data = [
                    'error_data' => '查找不到对应的from',
                    'remarks' => $e->getMessage()
                ];
                Error::addErrorLog($data);
            }
            $bool = $this->handleArr($result['sign'], $sign, $result['ip'], $ip);
            Redis::hMset($redis_hash_key, $result);
        }

        if($bool == 'success'){
            return 'success';
        }
        return $bool;

    }

    /**
     * 字符串切割 判断标识码或者ip是否在数组里面
     * @param $sign_str 限制标识码的字符串
     * @param $sign 限制标识码
     * @param $ip_str ip黑名单的字符串
     * @param $ip ip黑名单
     * @return bool
     */
    private function handleArr($sign_str,$sign, $ip_str, $ip)
    {
        $sign_str = str_replace('"','', $sign_str);
        $sign_arr = explode('%',$sign_str);
        if(in_array($sign, $sign_arr) == false){
            return '标识码不存在';
        }

        $ip_str = str_replace('"','', $ip_str);
        $ip_arr = explode('%',$ip_str);
        if(in_array($ip, $ip_arr) == true){
            return 'ip限制';
        }

        return 'success';
    }
    # 获取当前账号是否允许重复
    private function getRepeat($record_id)
    {
        $arr = explode('_', $record_id);
        $from = $arr['0'];
        $redis_hash_key = config('redis.account').$from;
        $arr_info = Redis::hget($redis_hash_key);
        $logo = null;
        if(key_exists('repeat', $arr_info) && key_exists('logo', $arr_info) && key_exists('id', $arr_info)){
            $repeat = $arr_info['repeat'];
            $logo = $arr_info['logo'];
            $this->user_id = $arr_info['id'];
        }else{
            try{
                $model = new Account();
                $arr_info = $model->where('name', '=', $from)
                    ->find()
                    ->toArray();
                # 同步写入redis
                Redis::hMset($redis_hash_key, $arr_info);
                $repeat = $arr_info['repeat'];
                $logo = $arr_info['logo'];
            }catch (Exception $e){
                $data = [
                    'error_data' => '尝试添加不存在的from标识',
                    'remarks' => $e->getMessage()
                ];
                Error::addErrorLog($data);
                return -1;
            }
        }
        return [
            'logo' => $logo,
            'repeat' => $repeat
        ];
    }

    /**
     * 先判断record_id是否存在，存在则移除
     * @param $record_id
     * @param $from
     * @return bool
     */
    private function check_record_id($arr_record_id)
    {
        $redis_hash_key = config('redis.record_id');
        $result = Redis::sRm($redis_hash_key, $arr_record_id['id']);
        if(!$result){
            return 'no record_id';
        }
        return 'success';
    }

    # 查找该平台是否出现重复的手机号码
    private function findPhone($model, $phone, $from, $type)
    {
        return $model->where('from', '=', $from)
            ->where('type', '=', $type)
            ->where('phone', '=', $phone)
            ->find();
    }
    # 检查手机号码是否已经在改商户注册
    private function checkHasPhone($phone, $type, $logo, $registered_time)
    {
        $info = new Info();
        $data = $info->checkPhone($phone, $type, $logo);
        if(count($data) == 0 || empty($data) == true){
            return false;
        }
//        if($data['add_time'] > strtotime($registered_time)){
//            return false;
//        }
        return true;
    }

    /**
     * 添加手机号码到撞库数据库true
     * @param $phone
     * @param $logo
     */
    private function addPhoneToTrue($phone, $logo)
    {
        $add_phone = new UserPhone();
        $add_phone->add_user_true($phone, $logo, 2);
    }
}